﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;
using EnvDTE;
using System.Windows.Forms;
using Sofire.Data;
using System.Data;
using SofireXSqlEntityGenerator.Core;
using System.IO;

namespace SofireXSqlEntityGenerator
{
    public static class VSEx
    {
        ///*
        // * 查看 F:\MyOpenSource\C#\InfinitiesLoop-VSNewFile-a002578
        // */
        public static string GetAllCommandNames(this DTE2 _applicationObject)
        {
            CommandBars commandBars = (CommandBars)_applicationObject.CommandBars;
            StringBuilder sb = new StringBuilder();

            foreach(CommandBar cbar in commandBars)
            {
                sb.AppendLine(cbar.Name);
            }

            return sb.ToString();
        }


        /// <summary>
        /// 获取当前【Visual Studio】集成开发环境选中的第一个项目。
        /// <para>修改：2010-01-07。</para>
        /// </summary>
        /// <param name="ide">【Visual Studio】集成开发环境。</param>
        /// <param name="directory">项目目录。</param>
        /// <param name="ns">命名空间。</param>
        public static Project GetSelectingProject(this _DTE ide, out string directory, out string ns)
        {
            directory = null;
            ns = null;
            if(ide != null && ide.SelectedItems != null && ide.SelectedItems.Count > 0)
            {
                SelectedItem selectedProject = ide.SelectedItems.GetFirst();

                if(selectedProject.Project != null)
                {// 选中的是一个项目文件
                    directory = Path.GetDirectoryName(selectedProject.Project.FullName);
                    ns = selectedProject.Project.GetNamespace();
                    return selectedProject.Project;// 返回选中项的【项目文件】格式
                }
                else if(selectedProject.ProjectItem != null)
                {// 选中的是一个文件，或文件夹，或者其他
                    directory = Path.GetDirectoryName(selectedProject.ProjectItem.GetFullPath());
                    ns = selectedProject.ProjectItem.GetNamespace();
                    var pj = selectedProject.ProjectItem.ContainingProject;
                    if(string.IsNullOrEmpty(ns)) ns = pj.GetNamespace();
                    return pj;// 返回选中项的【文件或文件夹】格式的项目文件
                }
                // 否则，可能选中的是解决方案
            }
            return null;
        }

        /// <summary>
        /// 获取【项】的完整目录。
        /// <para>修改：2010-01-06。</para>
        /// </summary>
        /// <param name="item">【项】。</param>
        public static string GetFullPath(this ProjectItem item)
        {
            try
            {
                var value = item.Properties.Item("FullPath").Value;
                if(value == null) return string.Empty;
                return value.ToString();
            }
            catch(Exception) { }
            return string.Empty;
        }


        /// <summary>
        /// 获取【项】的默认命名空间。
        /// <para>修改：2010-01-06。</para>
        /// </summary>
        /// <param name="item">项目项。</param>
        public static string GetNamespace(this ProjectItem item)
        {
            try
            {
                return item.Properties.Item("DefaultNamespace").Value.ToString();
            }
            catch(Exception) { }
            return string.Empty;
        }

        /// <summary>
        /// 获取【项目】的默认命名空间。
        /// <para>修改：2010-01-06。</para>
        /// </summary>
        /// <param name="item">【项目】。</param>
        public static string GetNamespace(this Project item)
        {
            try
            {
                return item.Properties.Item("DefaultNamespace").Value.ToString();
            }
            catch(Exception) { }
            return string.Empty;
        }

        /// <summary>
        /// 尝试获取指定索引的【项】的【项】。
        /// <para>修改：2010-01-06。</para>
        /// </summary>
        /// <param name="item">【项】。</param>
        /// <param name="index">从【0】开始的索引。</param>
        public static ProjectItem GetItem(this ProjectItem item, int index)
        {
            try
            {
                return item.ProjectItems.Item(index - 1);
            }
            catch(Exception) { }
            return null;
        }

        /// <summary>
        /// 尝试获取指定索引的【项目】的【项】。
        /// <para>修改：2010-01-06。</para>
        /// </summary>
        /// <param name="project">【项目】。</param>
        /// <param name="index">从【0】开始的索引。</param>
        public static ProjectItem GetItem(this Project project, int index)
        {
            try
            {
                return project.ProjectItems.Item(index - 1);
            }
            catch(Exception) { }
            return null;
        }

        /// <summary>
        /// 尝试获取指定索引的【项】的【项】。
        /// <para>修改：2010-01-07。</para>
        /// </summary>
        /// <param name="item">【项】。</param>
        /// <param name="name">项的名称。</param>
        public static ProjectItem GetItem(this ProjectItem item, string name)
        {
            try
            {
                return item.ProjectItems.Item(name);
            }
            catch(Exception) { }
            return null;
        }

        /// <summary>
        /// 尝试获取指定索引的【项目】的【项】。
        /// <para>修改：2010-01-06。</para>
        /// </summary>
        /// <param name="project">【项目】。</param>
        /// <param name="name">项的名称。</param>
        public static ProjectItem GetItem(this Project project, string name)
        {
            try
            {
                return project.ProjectItems.Item(name);
            }
            catch(Exception) { }
            return null;
        }

        /// <summary>
        /// 尝试【SelectedItems】中的第一个【SelectedItem】。
        /// <para>修改：2010-01-06。</para>
        /// </summary>
        /// <param name="items">【项目】。</param>
        public static SelectedItem GetFirst(this SelectedItems items)
        {
            try
            {
                if(items != null && items.Count > 0) return items.Item(1);
            }
            catch(Exception) { }
            return null;
        }

        public static void AddCommandToMenuBarTools(this DTE2 _applicationObject, AddIn _addInInstance
            , string name, string text, string tooltip)
        {
            object[] contextGUIDS = new object[] { };
            Commands2 commands = (Commands2)_applicationObject.Commands;
            string toolsMenuName = "Tools";

            //将此命令置于“工具”菜单上。
            //查找 MenuBar 命令栏，该命令栏是容纳所有主菜单项的顶级命令栏:
            CommandBar menuBarCommandBar = ((CommandBars)_applicationObject.CommandBars)["MenuBar"];

            //在 MenuBar 命令栏上查找“工具”命令栏:
            CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
            CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;

            //如果希望添加多个由您的外接程序处理的命令，可以重复此 try/catch 块，
            //  只需确保更新 QueryStatus/Exec 方法，使其包含新的命令名。
            try
            {
                //将一个命令添加到 Commands 集合:
                Command command = commands.AddNamedCommand2(_addInInstance, name, text, tooltip, true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);

                //将对应于该命令的控件添加到“工具”菜单:
                if((command != null) && (toolsPopup != null))
                {
                    command.AddControl(toolsPopup.CommandBar, 1);
                }
            }
            catch(System.ArgumentException)
            {
                //如果出现此异常，原因很可能是由于具有该名称的命令
                //  已存在。如果确实如此，则无需重新创建此命令，并且
                //  可以放心忽略此异常。
            }
        }
        public static readonly Dictionary<string, DataTable> ColumnsCache = new Dictionary<string, DataTable>(StringComparer.CurrentCultureIgnoreCase);

        public static QueryEngineBase CreateEngine(QueryEngineProvider provider, string connectionString)
        {
            switch(provider)
            {
                case QueryEngineProvider.Microsoft_SQL_Server:
                    return new MsSqlQuery(connectionString);
                   
                case QueryEngineProvider.Microsoft_OleDb_Before_2003:
                    break;
                case QueryEngineProvider.Microsoft_OleDb_After_2007:
                    break;
                case QueryEngineProvider.SQLite:

                    return new SQLiteQuery(connectionString);

                case QueryEngineProvider.Oracle:
                  
                    //OracleQuery.LicensePath = Path.Combine(Path.GetDirectoryName(Connect.AddInInstance.SatelliteDllPath), OracleQuery.DDTekLic);
                    return new OracleQuery(connectionString);
                case QueryEngineProvider.MySql:
                    break;
                default:
                    break;
            }
            return null;
        }

        public static string GetAliasName(string name)
        {
            StringBuilder builder = new StringBuilder();
            GetAliasName(builder, name);
            return builder.ToString();
        }
        private static void GetAliasName(StringBuilder builder, string columnName)
        {
            builder.Clear();
            char last = '\0';
            char c;
            var length = columnName.Length;
            for(int i = 0 ; i < length ; i++)
            {
                //Userid
                c = columnName[i];
                if(i == 0
                    || last == '_'
                    || (char.ToUpper(last) == 'I'
                        && char.ToUpper(c) == 'D'
                        && (i - 2 < 0 || char.ToUpper(columnName[i - 2]) != 'L'))
                    || (char.ToUpper(c) == 'I'
                        && (i + 1) < length
                        && char.ToUpper(columnName[i + 1]) == 'D'
                        && char.ToUpper(last) != 'L'))
                {
                    builder.Append(char.ToUpper(c));
                }
                else
                {
                    if(c != '_') builder.Append(char.ToLower(c));
                }
                last = c;
            };
        }

        public static void FillFieldTypeItems(DataGridViewComboBoxColumn col_FieldType)
        {
            col_FieldType.Items.Add(Types.Boolean.Name);
            col_FieldType.Items.Add(Types.Int16.Name);
            col_FieldType.Items.Add(Types.Int32.Name);
            col_FieldType.Items.Add(Types.Int64.Name);
            col_FieldType.Items.Add(Types.Single.Name);
            col_FieldType.Items.Add(Types.Double.Name);
            col_FieldType.Items.Add(Types.Decimal.Name);
            col_FieldType.Items.Add(Types.DateTime.Name);
            col_FieldType.Items.Add(Types.String.Name);
            col_FieldType.Items.Add(Types.ByteArray.Name);

        }

        public static Result<DataTable> RefreshColumns(SqlGeneratorBase generator, string tableName)
        {
            var emptyTableResult = generator.GetEmptyTable(tableName);
            if(emptyTableResult.IsFailed) return emptyTableResult.Exception;
            var columnTableResult = generator.GetTableColumns(tableName);
            if(columnTableResult.IsFailed) return columnTableResult.Exception;

            var columnsTable = columnTableResult.Value;
            // 是否选中
            columnsTable.Columns.Add("IsSelected", Types.Boolean);
            // 别名
            var aliasNameColumn = columnsTable.Columns.Add("AliasName", Types.String);
            // 条件选中(SQL生成专用)
            columnsTable.Columns.Add("IsWhereSelected", Types.Boolean);
            // 数据类型
            var typeColumn = columnsTable.Columns.Add("FieldType", Types.String);
            StringBuilder builder = new StringBuilder();
            var isNullableColumn = columnsTable.Columns["IsNullable"];
            foreach(DataColumn column in emptyTableResult.Value.Columns)
            {
                var rows = columnsTable.Select("FiledName='" + column.ColumnName + "'");
                if(rows.Length == 0) continue;
                var row = rows[0];
                row[typeColumn] = column.DataType.Name;
                if(GlobalSetting.AutoAliasName)
                {
                    GetAliasName(builder, column.ColumnName);
                    row[aliasNameColumn] = builder.ToString();
                }
                else
                {
                    row[aliasNameColumn] = column.ColumnName;
                }
                if(GlobalSetting.AlwaysNullable) row[isNullableColumn] = 1;
            }

            VSEx.ColumnsCache[tableName] = columnsTable;
            return columnsTable;
        }

        /// <summary>
        /// 判断一个返回结果是否成功。如果失败，将会弹出异常信息。
        /// </summary>
        /// <param name="owner">控件拥有者。</param>
        /// <param name="result">返回结果。</param>
        /// <returns>返回结果的状态。</returns>
        public static bool IsSuccess(this Control owner, IResult result)
        {
            return VSEx.IsSuccess(owner, result, string.Empty);
        }

        /// <summary>
        /// 判断一个返回结果是否成功。如果失败，将会弹出异常信息。
        /// </summary>
        /// <param name="owner">控件拥有者。</param>
        /// <param name="result">返回结果。</param>
        /// <param name="other">其他信息。</param>
        /// <returns>返回结果的状态。</returns>
        public static bool IsSuccess(this Control owner, IResult result, string other)
        {
            if(result != null && !result.IsIgnored)
            {
                if(result.IsSucceed) return true;
                ShowError(owner, result.ToString() + other);
            }
            return false;
        }

        /// <summary> 弹出提示，显示错误信息。
        /// </summary>
        /// <param name="content">文本内容。</param>
        public static void ShowError(string content) { ShowError(null, content); }

        /// <summary> 弹出提示，显示错误信息。
        /// </summary>
        /// <param name="control">窗体。</param>
        /// <param name="content">文本内容。</param>
        public static void ShowError(this Control control, string content)
        {
            Show(new ShowFormFields()
            {
                Control = control,
                Contet = content,
                MessageBoxIcon = MessageBoxIcon.Error
            });
        }

        /// <summary> 弹出提示，显示消息。
        /// </summary>
        /// <param name="content">文本内容。</param>
        public static void ShowInfo(string content) { ShowInfo(null, content); }

        /// <summary> 弹出提示，显示消息。
        /// </summary>
        /// <param name="control">窗体。</param>
        /// <param name="content">文本内容。</param>
        public static void ShowInfo(this Control control, string content)
        {
            Show(new ShowFormFields()
            {
                Control = control,
                Contet = content,
                MessageBoxIcon = MessageBoxIcon.Information
            });
        }

        /// <summary> 弹出提示，显示提示，返回【true】则表明按了“是”。
        /// </summary>
        /// <param name="content">文本内容。</param>
        public static bool ShowYesNo(string content) { return ShowYesNo(null, content); }

        /// <summary> 弹出提示，显示提示，返回【true】则表明按了“是”。
        /// </summary>
        /// <param name="control">窗体。</param>
        /// <param name="content">文本内容。</param>
        public static bool ShowYesNo(this Control control, string content)
        {
            return Show(new ShowFormFields()
            {
                Control = control,
                Contet = content,
                MessageBoxButtons = System.Windows.Forms.MessageBoxButtons.YesNo,
                MessageBoxIcon = MessageBoxIcon.Question
            }) == DialogResult.Yes;
        }

        private static DialogResult Show(ShowFormFields fields)
        {
            if(fields.Control != null && fields.Control.InvokeRequired) return (DialogResult)fields.Control.Invoke(new Func<ShowFormFields, DialogResult>(Show), fields);
            else return MessageBox.Show(fields.Control, fields.Contet, "温馨提示", fields.MessageBoxButtons, fields.MessageBoxIcon);
        }

        private class ShowFormFields
        {
            public Control Control;
            public string Contet;
            public MessageBoxButtons MessageBoxButtons = MessageBoxButtons.OK;
            public MessageBoxIcon MessageBoxIcon = MessageBoxIcon.None;
        }
    }
}
